use std::io::{Error, ErrorKind};
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::ops::Add;
use std::str::FromStr;

#[derive(Clone,PartialEq,Eq,Hash,Debug)]
pub enum Address {
    SocketAddress(SocketAddr),
    DomainNameAddress(String,u16),
}

#[derive(Debug)]
pub struct AddressError{
    message: String,
}

impl AddressError {
    pub fn as_str(&self) -> &str {
        self.message.as_str()
    }
}

impl From<AddressError> for Error{
    fn from(e: AddressError) -> Self {
        Error::new(ErrorKind::Other, format!("address error {:?}", e.message))
    }
}

impl Default for Address {
    fn default() -> Self {
        Address::new_dummy_address()
    }
}

impl FromStr for Address{
    type Err = AddressError;

    fn from_str(s: &str) -> Result<Address, AddressError> {
        match s.parse::<SocketAddr>() {
            Ok(addr) => {
                println!("33line from_str function of parse address result: -> {}",addr.clone());
                Ok(Address::SocketAddress(addr))},
            Err(..) => {
                let mut sp = s.split(":");
                match (sp.next(),sp.next()) {
                    (Some(dn),Some(port)) => match port.parse::<u16>() {
                        Ok(port) => Ok(Address::DomainNameAddress(dn.to_owned(),port)),
                        Err(..) => Err(AddressError{
                        message: s.to_owned().to_string().add("1111111111111111"),
                        })
                    },
                    (Some(dn),None) => {
                        Ok(Address::DomainNameAddress(dn.to_owned(),80))
                    },
                    _ => Err(AddressError{
                        message: s.to_owned().to_string().add("22222222222222"),
                    })
                }
            },
        }
    }
}

impl Address {
    #[inline]
    pub fn new_dummy_address() -> Address {
        Address::SocketAddress(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0,0,0,0)),0))
    }
}

impl From<SocketAddr> for Address {
    fn from(s: SocketAddr) -> Address {
        Address::SocketAddress(s)
    }
}

impl From<(String, u16)> for Address {
    fn from((dn, port): (String, u16)) -> Address {
        Address::DomainNameAddress(dn, port)
    }
}

impl From<&Address> for Address {
    fn from(addr: &Address) -> Address {
        addr.clone()
    }
}